package com.blacktea.magicapi.policy.magicapiuiuser;

import cn.hutool.core.lang.Validator;
import com.blacktea.magicapi.base.utils.IpUtils;
import com.blacktea.magicapi.entites.domain.MguMagicUiUser;
import com.blacktea.magicapi.entites.dto.UiUserDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.ssssssss.magicapi.exception.MagicLoginException;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: black tea
 * @date: 2022/1/1 23:12
 */
public interface UiUserPolicy {

    Logger log = LoggerFactory.getLogger(UiUserPolicy.class);

    /**
     * 通过 token 获得 magic-api UI 用户dto
     * @see UiUserDto
     */
    UiUserDto getUser(String token);

    /**
     * 生成token
     */
    String buildToken(UiUserDto uiUser);

    /**
     * 获取所有已登录的UI用户
     */
    List<UiUserDto> users();

    /**
     * 移除该 token 对应的UI用户,可以理解为登出
     * @param token
     */
    void removeByToken(String token);

    /**
     * 通过用户名称获取该账号被存储的所有登录信息
     * @param username 用户名称
     * @return List<UiUserDto>
     */
    List<UiUserDto> getByUsername(String username);

    /**
     * 限制单用户同时在线次数
     * @param username 用户名称
     * @param limitLogin 限制同时在线次数
     * @param currentLogin 相同UI 用户在线次数
     * @throws MagicLoginException
     */
    default void limitLogin(String username, Integer limitLogin, Integer currentLogin) throws MagicLoginException {
        if (Validator.isNotNull(limitLogin) && limitLogin <= currentLogin){
            throw new MagicLoginException("当前账号达到同时在线限制人数,拒绝登录");
        }
    }

    /**
     * 检查账号是否被锁定
     * @param user 用户信息
     */
    default void checkLockAccount(MguMagicUiUser user) throws MagicLoginException {
        if (user.isLock()){
            throw new MagicLoginException("当前账号被锁定,拒绝登录");
        }
    }

    /**
     * 获取请求的ip
     */
    default String getIp(){
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();
        return IpUtils.getIpAddr(request);
    }

    /**
     * 获取对应用户{@link MguMagicUiUser}的白名单
     */
    String getWhitelist(MguMagicUiUser user);

    /**
     * 在对应用户的白名单中添加集合ip
     * @param user 对应用户{@link MguMagicUiUser}
     * @param ips 需要添加的ip集合值
     */
    void putWhitelist(MguMagicUiUser user, List<String> ips);

    /**
     * 在对应用户的白名单中移除集合ip
     * @param user 对应用户{@link MguMagicUiUser}
     * @param matchIps 需要移除的ip集合值
     */
    void removeByIpWhitelist(MguMagicUiUser user, List<String> matchIps);

    /**
     * 将对应用户的白名单清空
     * @param user 对应用户{@link MguMagicUiUser}
     */
    void removeAllWhitelist(MguMagicUiUser user);

    /**
     * 将白名单中与Map对应的Key相同的值用Value替换
     * @param user 对应用户{@link MguMagicUiUser}
     * @param replaceIpMap 需要替换的Map,Map.key 对应 黑名单的值,Map.value 对应替换后的值
     */
    void replaceWhitelist(MguMagicUiUser user, Map<String,String> replaceIpMap);

    /**
     * 获取对应用户{@link MguMagicUiUser}的黑名单
     */
    String getBlacklist(MguMagicUiUser user);

    /**
     * 在对应用户的黑名单中添加集合ip
     * @param user 对应用户{@link MguMagicUiUser}
     * @param ips 需要添加的ip集合值
     */
    void putBlacklist(MguMagicUiUser user, List<String> ips);

    /**
     * 在对应用户的黑名单中移除集合ip
     * @param user 对应用户{@link MguMagicUiUser}
     * @param matchIps 需要移除的ip集合值
     */
    void removeByIpBlacklist(MguMagicUiUser user, List<String> matchIps);

    /**
     * 将对应用户的黑名单清空
     * @param user 对应用户{@link MguMagicUiUser}
     */
    void removeAllBlacklist(MguMagicUiUser user);

    /**
     * 将黑名单中与Map对应的Key相同的值用Value替换
     * @param user 对应用户{@link MguMagicUiUser}
     * @param replaceIpMap 需要替换的Map,Map.key 对应 黑名单的值,Map.value 对应替换后的值
     */
    void replaceBlacklist(MguMagicUiUser user, Map<String,String> replaceIpMap);

    /**
     * 用户登录IP是否是在黑名单内
     * @param ipWhiteConfig 白名单配置,以逗号隔开(ipWhiteConfig = null/"" 表示没有白名单要求)
     * @see IpUtils main() 测试用例
     */
    default void hasIpBlacklist(String ipWhiteConfig) throws MagicLoginException {
        if (Validator.isEmpty(ipWhiteConfig)){
            // 没有黑名单要求
            return;
        }
        String ip = this.getIp();
        if (IpUtils.checkLoginIP(ip,ipWhiteConfig)){
            log.info("在黑名单内,该ip:【{}】,黑名单:【{}】。",ip,ipWhiteConfig);
            throw new MagicLoginException("所在的区域IP在黑名单范围内,拒绝登录");
        }
    }

    /**
     * 用户登录IP是否是在白名单内
     * @param ipWhiteConfig 白名单配置,以逗号隔开(ipWhiteConfig = null/"" 表示没有白名单要求)
     * @see IpUtils main() 测试用例
     */
    default void hasIpWhitelists(String ipWhiteConfig) throws MagicLoginException {
        if (Validator.isEmpty(ipWhiteConfig)){
            // 没有白名单要求
            return;
        }
        String ip = this.getIp();
        if (!IpUtils.checkLoginIP(ip,ipWhiteConfig)){
            log.info("不在白名单内,该ip:【{}】,白名单:【{}】。",ip,ipWhiteConfig);
            throw new MagicLoginException("所在的区域IP不在白名单范围内,拒绝登录");
        }
    }

}
